using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
using CHEnhanceEfCore.Common;
using CHEnhanceEfCore.Config.Cache;
using CHEnhanceEfCore.Config.Log;
using CHEnhanceEfCore.Config.MQ;
using CHEnhanceEfCore.Config.MQ.factory;
using CHEnhanceEfCore.Config.MQ.listen;
using CHEnhanceEfCore.Config.Schedule.config;
using CHEnhanceEfCore.Config.Schedule.jobs;
using CHEnhanceEfCore.DataBase;
using CHEnhanceEfCore.Filter;
using CHEnhanceEfCore.Interceptor;
using CHEnhanceEfCore.Repository;
using CHEnhanceEfCore.Service;
using CHEnhanceEfCore.Service.impl;
using CHEnhanceEfCore.System;
using Elastic.Clients.Elasticsearch;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Nacos.AspNetCore.V2;
using Quartz;
using Quartz.Impl;
using StackExchange.Redis;
using IInterceptor = Microsoft.EntityFrameworkCore.Diagnostics.IInterceptor;

namespace CHEnhanceEfCore
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            configController(services);
            configSwagger(services);
            configMysql(services);
            configAppSettings(services);
            configCache(services);
            configJobs(services);
            configIServiceCollection(services);
            configTransientService(services);
            configMq(services);
            configElasticSearch(services);
            configJwt(services);
            configCros(services);
            configLogs(services);
            // configNacos(services);
        }

        private void configNacos(IServiceCollection services)
        {
            //远程拉取nacos上面的配置
            // services.AddNacosV2Config(Configuration);
            services.AddNacosAspNet(Configuration);
        }

        private void configLogs(IServiceCollection services)
        {
            services.AddSingleton<LogUtils>();
        }

        private void configElasticSearch(IServiceCollection services)
        {
            ElasticsearchClient client = new ElasticsearchClient(new Uri("http://127.0.0.1:9200"));
            services.AddSingleton(client);
        }

        private void configCros(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("localhost", builder =>
                {
                    builder.SetIsOriginAllowedToAllowWildcardSubdomains()
                        .SetIsOriginAllowed(origin => new Uri(origin).Host == "localhost")
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials();
                });
            });
        }

        private void configTransientService(IServiceCollection services)
        {
            services.AddTransient<IUserService, UserServiceImpl>();
            services.AddTransient<IRoleService, RoleServiceImpl>();
            services.AddTransient<IUserTaskService, UserTaskServiceImpl>();
            services.AddTransient<UserTaskRepository, UserTaskRepository>();
        }

        private void configJwt(IServiceCollection services)
        {
            string key = "A86DA130-1B95-4748-B3B2-1B6AA9F2F743";
            var secret = Encoding.ASCII.GetBytes(key);
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuer = false, //是否验证Issuer
                    //ValidIssuer = configuration["Jwt:Issuer"], //发行人Issuer
                    ValidateAudience = false, //是否验证Audience
                    //ValidAudience = configuration["Jwt:Audience"], //订阅人Audience
                    ValidateIssuerSigningKey = true, //是否验证SecurityKey
                    IssuerSigningKey = new SymmetricSecurityKey(secret), //SecurityKey
                    //ValidateLifetime = true, //是否验证失效时间
                    ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值，解决服务器端时间不同步问题（秒）
                    //RequireExpirationTime = true
                };
            });
            services.AddAuthorization(options => { options.AddPolicy("UserPolicy", policy => { policy.RequireRole("user", "admin"); }); });
            services.AddAuthorization(options => { options.AddPolicy("AdminPolicy", policy => { policy.RequireRole("admin"); }); });
        }

        private void configIServiceCollection(IServiceCollection services)
        {
            services.AddSingleton(services);
        }

        private void configMq(IServiceCollection services)
        {
            services.AddHostedService<MqService>();
            //这里采用的是rabbitmq factory
            services.AddSingleton<RabbitMqFactory, RabbitMqFactory>();
            services.AddSingleton<IQueueListen, OrderQueueListen>();
            services.AddTransient<RabbitMqTemplate, RabbitMqTemplate>();
            Console.WriteLine("config rabbitMq success");
        }

        /// <summary>
        /// configJobs
        /// </summary>
        /// <param name="services"></param>
        private void configJobs(IServiceCollection services)
        {
            services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
            services.AddSingleton<QuartzJobFactory, QuartzJobFactory>();
            services.AddSingleton<QuartzConfigFactory>();
            services.AddHostedService<QuartzBackgroundService>();
            services.AddTransient<HelloJobs>();
        }

        /// <summary>
        /// configSwagger
        /// </summary>
        /// <param name="services"></param>
        private static void configSwagger(IServiceCollection services)
        {
            services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo {Title = "CHEnHanceEfCore", Version = "v1"}); });
        }

        /// <summary>
        /// configController
        /// </summary>
        /// <param name="services"></param>
        private static void configController(IServiceCollection services)
        {
            services.AddControllers(options =>
            {
                //添加拦截器
                options.Filters.Add<ActionInterceptor>();
                //添加异常过滤器
                options.Filters.Add<GlobalExceptionFilter>();
                //添加权限拦截过滤器
                options.Filters.Add<PermissionAuthorizationFilter>();
            });
        }

        /// <summary>
        /// 配置mysql
        /// </summary>
        /// <param name="services"></param>
        private void configMysql(IServiceCollection services)
        {
            //注册mysql
            services.AddDbContext<ChEnhanceDbContext>(options => options
                .UseMySql(Configuration.GetConnectionString("ChEnhanceDbContext"),
                    MySqlServerVersion.LatestSupportedServerVersion)
                .AddInterceptors(new List<IInterceptor> {new EfCoreInterceptor()}));
        }

        /// <summary>
        /// 配置缓存
        /// </summary>
        /// <param name="services"></param>
        private static void configCache(IServiceCollection services)
        {
            var appSettings = services.BuildServiceProvider().GetService<AppSettings>();
            if (string.IsNullOrWhiteSpace(appSettings.RedisConfig)) return;
            services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(appSettings.RedisConfig));
            services.AddTransient<ICacheContext, RedisCacheContext>();
            Console.WriteLine("config redis success");
        }

        /// <summary>
        /// configAppSettings
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        private void configAppSettings(IServiceCollection services)
        {
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);
            var appSettings = appSettingsSection.Get<AppSettings>();
            services.AddSingleton(appSettings);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //注入serviceProvider
            OperationalComponentUtil.serviceProvider = app.ApplicationServices;
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SmartLockServer v1"));
            }

            app.UseCors("localhost");
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                //扫描controller
                endpoints.MapControllers();
            });
        }
    }
}